#include "form_factory_params.h"
#include "ui_form_factory_params.h"

// add nacessary includes here
#include "utils/configure/configure_bll.h"
#include "utils/algorithm/algorithm_bll_t1c.h"
#include "utils/can/can_vars.h"
#include "ui/share/form_prompt_dlg.h"
#include "ui/share/form_shield_dlg.h"
#include "ui/share/form_prompt_dlg.h"
#include "ui/share/my_tabbar_style.h"

enum EUM_PARAMS_TYPE { EPT_MOVE, EPT_SPEED };
enum EUM_MOTOR_TYPE_T1C {
    E_MTT1C_TRAY,
    E_MTT1C_MAG_SLEEVE,
    E_MTT1C_MAG_ROD,
    E_MTT1C_VERTIAL,
    E_MTT1C_PIPETTE
};

/*
 * Function:    FormFactoryParams
 * Description: The default constructor
 * Paramer:     void
 * Return:
 */
FormFactoryParams::FormFactoryParams(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::FormFactoryParams)
{
    qDebug() << Q_FUNC_INFO;

    ui->setupUi(this);
}

/*
 * FormHistoryResult:    ~FormFactoryParams
 * Description: The default destructor
 * Paramer:     void
 * Return:
 */
FormFactoryParams::~FormFactoryParams()
{
    qDebug() << Q_FUNC_INFO;

    delete ui;
}

/*
 * Function:    getInstance
 * Description: Get an instance of "FormFactoryParams" class, if exist, return it
 * Paramer:     QWidget *pParent - the pointer of QWidget class
 * Return:      the pointer of "FormFactoryParams" class
 */
FormFactoryParams* FormFactoryParams::getInstance(QWidget *pParent)
{
    static FormFactoryParams *pWidget = nullptr;
    if(!pWidget) {
        // Create a new object if it doesn't exist
        pWidget = new FormFactoryParams(pParent);
        if(nullptr == pWidget) return nullptr;

        // After constructing object, initialize the object
        pWidget->_initObj();

        // Init the window style
        pWidget->_initUi();
    }

    // Set the parent object
    if(pParent) pWidget->setParent(pParent);

    return pWidget;
}

/*
 * Function:    _initObj
 * Description: After constructing object, initialize the object
 * Paramer:     void
 * Return:      void
 */
void FormFactoryParams::_initObj()
{
    qDebug() << Q_FUNC_INFO;

    // Signal-slot initialization
    std::vector<bool> vecConnect;
    vecConnect.push_back(QObject::connect(this, SIGNAL(signalRefreshUI(int)), this, SLOT(slotRefreshUI(int)), static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)));
    for(int i=0; i<(int)vecConnect.size(); i++) {
        Q_ASSERT(vecConnect.at(i));
    }

    if(1 == 1) {
        // Get the move params
        ST_CFG_MOTOR_PARAMS_T1C stCfgMotorParams;
        int nRetVal = ConfigureBLL::getInstance(this)->loadMotorParamsT1C(stCfgMotorParams);
        if(0 == nRetVal) {
            // Update golobal public variables from struct
            _updatePublicVariables(stCfgMotorParams);
        }
    }

    if(2 == 2) {
        // Get the speed params
        ST_CFG_SPEED_PARAMS stCfgSpeedParams;
        int nRetVal = ConfigureBLL::getInstance(this)->loadSpeedParams(stCfgSpeedParams);
        if(0 == nRetVal) {
            // Update golobal public variables
            if(0 < stCfgSpeedParams.nMotorSpeedHigh) MotorVars_T1C::nMotorSpeedHigh = stCfgSpeedParams.nMotorSpeedHigh;
            if(0 < stCfgSpeedParams.nMotorSpeedMedium) MotorVars_T1C::nMotorSpeedMedium = stCfgSpeedParams.nMotorSpeedMedium;
            if(0 < stCfgSpeedParams.nMotorSpeedLow) MotorVars_T1C::nMotorSpeedLow = stCfgSpeedParams.nMotorSpeedLow;
        }
    }
}

/*
* Function:		_initUi
* Description:	Init the window style
* Paramer:		void
* Return:		void
*/
void FormFactoryParams::_initUi()
{
    qDebug() << Q_FUNC_INFO;

    // Displays the background image of the window
    QWidget::setAttribute(Qt::WA_StyledBackground);

    SET_STYLE_SHEET(QString(":/%1/factory/factory_params/%2.qss").arg("skin_1").arg(this->objectName()));

    QValidator *vldValue = new QRegExpValidator(QRegExp("^[0-9]{1,4}([.][0-9]{1,2})?$"));

    ui->lineEdit_GrabSleelveDepth->setValidator(vldValue);
    ui->lineEdit_GrabSleelveDepth_2->setValidator(vldValue);
    ui->lineEdit_TrayMaxOffset->setValidator(vldValue);
    ui->lineEdit_TrayMaxOffset2->setValidator(vldValue);
    ui->lineEdit_SleelveSinking->setValidator(vldValue);
    ui->lineEdit_MagneticDepth->setValidator(vldValue);
    ui->lineEdit_GrabTipsOffset->setValidator(vldValue);
    ui->lineEdit_TipsMixing->setValidator(vldValue);
    ui->lineEdit_SuctionKit->setValidator(vldValue);
    ui->lineEdit_SpitKit->setValidator(vldValue);
    ui->lineEdit_PiercingSinking->setValidator(vldValue);

    ui->lineEdit_GrabSleelveDepth->setInputMethodHints(Qt::ImhDigitsOnly);
    ui->lineEdit_GrabSleelveDepth_2->setInputMethodHints(Qt::ImhDigitsOnly);
    ui->lineEdit_TrayMaxOffset->setInputMethodHints(Qt::ImhDigitsOnly);
    ui->lineEdit_TrayMaxOffset2->setInputMethodHints(Qt::ImhDigitsOnly);
    ui->lineEdit_SleelveSinking->setInputMethodHints(Qt::ImhDigitsOnly);
    ui->lineEdit_MagneticDepth->setInputMethodHints(Qt::ImhDigitsOnly);
    ui->lineEdit_GrabTipsOffset->setInputMethodHints(Qt::ImhDigitsOnly);
    ui->lineEdit_TipsMixing->setInputMethodHints(Qt::ImhDigitsOnly);
    ui->lineEdit_SuctionKit->setInputMethodHints(Qt::ImhDigitsOnly);
    ui->lineEdit_SpitKit->setInputMethodHints(Qt::ImhDigitsOnly);
    ui->lineEdit_PiercingSinking->setInputMethodHints(Qt::ImhDigitsOnly);

    QValidator *vldDigit = new QRegExpValidator(QRegExp("\\d{4}$"));
    ui->lineEdit_High->setValidator(vldDigit);
    ui->lineEdit_Medium->setValidator(vldDigit);
    ui->lineEdit_Low->setValidator(vldDigit);

    ui->horizontalSlider_High->setRange(1, 3000);
    ui->horizontalSlider_Medium->setRange(1, 3000);
    ui->horizontalSlider_Low->setRange(1, 3000);

    ui->lineEdit_High->setInputMethodHints(Qt::ImhDigitsOnly);
    ui->lineEdit_Medium->setInputMethodHints(Qt::ImhDigitsOnly);
    ui->lineEdit_Low->setInputMethodHints(Qt::ImhDigitsOnly);

    if(0) {
        ST_CFG_LOGIN_INFO stCfgLoginInfo;
        ConfigureBLL::getInstance(this)->loadLoginInfo(stCfgLoginInfo);

        if("factory" != stCfgLoginInfo.sLastUser)
            ui->tabWidget_Params->setTabEnabled(1, false);
    }

    ui->tabWidget_Params->tabBar()->hide();
}

/*
* Function:		changeEvent
* Description:	Triggers an event before it is switch language
* Paramer:		QShowEvent *event - the pointer of "QEvent"
* Return:		void
*/
void FormFactoryParams::changeEvent(QEvent *e)
{
    switch (e->type()) {
    case QEvent::LanguageChange:
    {
        ui->retranslateUi(this);

        switch (m_nType) {
        case EPT_MOVE:
            ui->label_PageTitle->setText(tr("Factory Params"));
            break;
        case EPT_SPEED:
            ui->label_PageTitle->setText(tr("Mixing Speed"));
            break;
        }

        qDebug() << Q_FUNC_INFO;
        break;
    }
    default:
        break;
    }

    QWidget::changeEvent(e);
}

/*
* Function:		slotRefreshUI
* Description:	The slot that refresh UI info
* Paramer:		void
* Return:		void
*/
void FormFactoryParams::slotRefreshUI(int nType)
{
    qDebug() << Q_FUNC_INFO;
    m_nType = nType;

    if(EPT_MOVE == m_nType) {
        ui->tabWidget_Params->setCurrentIndex(0);
        ui->label_PageTitle->setText(tr("Factory Params"));

        // Get the move params
        ST_CFG_MOTOR_PARAMS_T1C stCfgMotorParams;
        int nRetVal = ConfigureBLL::getInstance(this)->loadMotorParamsT1C(stCfgMotorParams);
        if(0 == nRetVal) {
            // Update golobal public variables from struct
            _updatePublicVariables(stCfgMotorParams);

            // Update UI data
            ui->lineEdit_PiercingSinking->setText(QString::number(stCfgMotorParams.fPierceOffsetY));
            ui->lineEdit_GrabSleelveDepth->setText(QString::number(stCfgMotorParams.fGrapSleeveOffsetY));
            ui->lineEdit_GrabSleelveDepth_2->setText(QString::number(stCfgMotorParams.fGrapSleeveOffsetY2));
            ui->lineEdit_TrayMaxOffset->setText(QString::number(stCfgMotorParams.fTrayMaxOffsetX));
            ui->lineEdit_TrayMaxOffset2->setText(QString::number(stCfgMotorParams.fTrayMaxOffsetX2));
            ui->lineEdit_SleelveSinking->setText(QString::number(stCfgMotorParams.fMixingSleeveOffsetY));
            ui->lineEdit_MagneticDepth->setText(QString::number(stCfgMotorParams.fMagneticMaxOffsetY));
            ui->lineEdit_GrabTipsOffset->setText(QString::number(stCfgMotorParams.fGrapTipsOffsetY));
            ui->lineEdit_TipsMixing->setText(QString::number(stCfgMotorParams.fTipsMixingOffsetY));
            ui->lineEdit_SuctionKit->setText(QString::number(stCfgMotorParams.fExtSwallowOffsetY));
            ui->lineEdit_SpitKit->setText(QString::number(stCfgMotorParams.fExtSpitOffsetY));
        }
    }

    if(EPT_SPEED == m_nType) {
        ui->tabWidget_Params->setCurrentIndex(1);
        ui->label_PageTitle->setText(tr("Mixing Speed"));

        // Get the speed params
        ST_CFG_SPEED_PARAMS stCfgSpeedParams;
        int nRetVal = ConfigureBLL::getInstance(this)->loadSpeedParams(stCfgSpeedParams);
        if(0 == nRetVal) {
            // Update golobal public variables
            if(0 >= stCfgSpeedParams.nMotorSpeedHigh) stCfgSpeedParams.nMotorSpeedHigh = MotorVars_T1C::nMotorSpeedHigh;
            if(0 >= stCfgSpeedParams.nMotorSpeedMedium) stCfgSpeedParams.nMotorSpeedMedium = MotorVars_T1C::nMotorSpeedMedium;
            if(0 >= stCfgSpeedParams.nMotorSpeedLow) stCfgSpeedParams.nMotorSpeedLow = MotorVars_T1C::nMotorSpeedLow;

            // Update UI data
            ui->lineEdit_High->setText(QString::number(stCfgSpeedParams.nMotorSpeedHigh));
            ui->lineEdit_Medium->setText(QString::number(stCfgSpeedParams.nMotorSpeedMedium));
            ui->lineEdit_Low->setText(QString::number(stCfgSpeedParams.nMotorSpeedLow));

            ui->horizontalSlider_High->setValue(stCfgSpeedParams.nMotorSpeedHigh);
            ui->horizontalSlider_Medium->setValue(stCfgSpeedParams.nMotorSpeedMedium);
            ui->horizontalSlider_Low->setValue(stCfgSpeedParams.nMotorSpeedLow);
        }
    }
}

/*
 * Function:    on_pushButton_Modify_clicked
 * Description: Save configuration info
 * Paramer:     void
 * Return:      void
 */
void FormFactoryParams::on_pushButton_Modify_clicked()
{
    // Prevent the button from clicking repeatedly quickly
    FormShieldDlg::getInstance(this)->show();
    if(EPT_MOVE == m_nType) {
        ST_CFG_MOTOR_PARAMS_T1C stCfgMotorParams;
        stCfgMotorParams.fPierceOffsetY = ui->lineEdit_PiercingSinking->text().trimmed().toFloat();
        stCfgMotorParams.fGrapSleeveOffsetY = ui->lineEdit_GrabSleelveDepth->text().trimmed().toFloat();
        stCfgMotorParams.fGrapSleeveOffsetY2 = ui->lineEdit_GrabSleelveDepth_2->text().trimmed().toFloat();
        stCfgMotorParams.fTrayMaxOffsetX = ui->lineEdit_TrayMaxOffset->text().trimmed().toFloat();
        stCfgMotorParams.fTrayMaxOffsetX2 = ui->lineEdit_TrayMaxOffset2->text().trimmed().toFloat();
        stCfgMotorParams.fMixingSleeveOffsetY = ui->lineEdit_SleelveSinking->text().trimmed().toFloat();
        stCfgMotorParams.fMagneticMaxOffsetY = ui->lineEdit_MagneticDepth->text().trimmed().toFloat();
        stCfgMotorParams.fGrapTipsOffsetY = ui->lineEdit_GrabTipsOffset->text().trimmed().toFloat();
        stCfgMotorParams.fTipsMixingOffsetY = ui->lineEdit_TipsMixing->text().trimmed().toFloat();
        stCfgMotorParams.fExtSwallowOffsetY = ui->lineEdit_SuctionKit->text().trimmed().toFloat();
        stCfgMotorParams.fExtSpitOffsetY = ui->lineEdit_SpitKit->text().trimmed().toFloat();

        if(0 >= stCfgMotorParams.fPierceOffsetY
                || 0 >= stCfgMotorParams.fGrapSleeveOffsetY
                || 0 >= stCfgMotorParams.fGrapSleeveOffsetY2
                || 0 >= stCfgMotorParams.fTrayMaxOffsetX
                || 0 >= stCfgMotorParams.fTrayMaxOffsetX2
                || 0 >= stCfgMotorParams.fMixingSleeveOffsetY
                || 0 >= stCfgMotorParams.fMagneticMaxOffsetY
                || 0 >= stCfgMotorParams.fGrapTipsOffsetY
                || 0 >= stCfgMotorParams.fTipsMixingOffsetY
                || 0 >= stCfgMotorParams.fExtSwallowOffsetY
                || 0 >= stCfgMotorParams.fExtSpitOffsetY) {
            FormPromptWidget::getInstance(this)->setPromptInfo(tr("Prompt"), tr("Params must be more than 0"));
            QTimer::singleShot(DEF_SEC_INTERVAL, this, [&]() {
                FormPromptWidget::getInstance(this)->hide();
            });
        }
        else {
            // Set the params
            int nRetVal = ConfigureBLL::getInstance(this)->saveMotorParamsT1C(stCfgMotorParams);
            if(0 == nRetVal) {
                // Update golobal public variables from struct
                _updatePublicVariables(stCfgMotorParams);

                FormPromptWidget::getInstance(this)->setPromptInfo(tr("Prompt"), tr("Save successfully"));
            }
            else {
                FormPromptWidget::getInstance(this)->setPromptInfo(tr("Prompt"), tr("Failed to setting params"));
            }

            QTimer::singleShot(DEF_SEC_INTERVAL, this, [&]() {
                FormPromptWidget::getInstance(this)->hide();
            });
        }
    }

    if(EPT_SPEED == m_nType) {
        ST_CFG_SPEED_PARAMS stCfgSpeedParams;
        stCfgSpeedParams.nMotorSpeedHigh = ui->lineEdit_High->text().toInt();
        stCfgSpeedParams.nMotorSpeedMedium = ui->lineEdit_Medium->text().toInt();
        stCfgSpeedParams.nMotorSpeedLow = ui->lineEdit_Low->text().toInt();

        if(1 > stCfgSpeedParams.nMotorSpeedHigh || 3000 < stCfgSpeedParams.nMotorSpeedHigh
                || 1 > stCfgSpeedParams.nMotorSpeedMedium || 3000 < stCfgSpeedParams.nMotorSpeedMedium
                || 1 > stCfgSpeedParams.nMotorSpeedLow || 3000 < stCfgSpeedParams.nMotorSpeedLow) {
            FormPromptWidget::getInstance(this)->setPromptInfo(tr("Prompt"), tr("The input value exceeds the range [1~3000]"));
            goto do_exit;
        }

        int nRetVal = ConfigureBLL::getInstance(this)->saveSpeedParams(stCfgSpeedParams);
        if(0 == nRetVal) {
            // Update golobal public variables
            if(0 <= stCfgSpeedParams.nMotorSpeedHigh) MotorVars_T1C::nMotorSpeedHigh = stCfgSpeedParams.nMotorSpeedHigh;
            if(0 <= stCfgSpeedParams.nMotorSpeedMedium) MotorVars_T1C::nMotorSpeedMedium = stCfgSpeedParams.nMotorSpeedMedium;
            if(0 <= stCfgSpeedParams.nMotorSpeedLow) MotorVars_T1C::nMotorSpeedLow = stCfgSpeedParams.nMotorSpeedLow;

            FormPromptWidget::getInstance(this)->setPromptInfo(tr("Prompt"), tr("Save successfully"));
        }
        else {
            FormPromptWidget::getInstance(this)->setPromptInfo(tr("Prompt"), tr("Failed to setting mixing speed"));
        }

        QTimer::singleShot(DEF_SEC_INTERVAL, this, [&]() {
            FormPromptWidget::getInstance(this)->hide();
        });
    }

do_exit:
    FormShieldDlg::getInstance(this)->hide();
}

void FormFactoryParams::on_horizontalSlider_High_valueChanged(int value)
{
    ui->lineEdit_High->setText(QString::number(value));
}

void FormFactoryParams::on_horizontalSlider_Medium_valueChanged(int value)
{
    ui->lineEdit_Medium->setText(QString::number(value));
}

void FormFactoryParams::on_horizontalSlider_Low_valueChanged(int value)
{
    ui->lineEdit_Low->setText(QString::number(value));
}

void FormFactoryParams::_updatePublicVariables(struct ST_CFG_MOTOR_PARAMS_T1C &stCfgMotorParams)
{
    // Update the public variables
    if(0 < stCfgMotorParams.fTrayMaxOffsetX)
        AlgorithmBLL_T1C::getInstance()->trip2step(MotorVars_T1C::nExitTrayMaxOffsetX, E_MTT1C_TRAY, stCfgMotorParams.fTrayMaxOffsetX);
    else
        AlgorithmBLL_T1C::getInstance()->step2trip(stCfgMotorParams.fTrayMaxOffsetX, E_MTT1C_TRAY, MotorVars_T1C::nExitTrayMaxOffsetX);

    if(0 < stCfgMotorParams.fTrayMaxOffsetX2)
        AlgorithmBLL_T1C::getInstance()->trip2step(MotorVars_T1C::nExitTrayMaxOffsetX2, E_MTT1C_TRAY, stCfgMotorParams.fTrayMaxOffsetX2);
    else
        AlgorithmBLL_T1C::getInstance()->step2trip(stCfgMotorParams.fTrayMaxOffsetX2, E_MTT1C_TRAY, MotorVars_T1C::nExitTrayMaxOffsetX2);

    if(0 < stCfgMotorParams.fGrapSleeveOffsetY)
        AlgorithmBLL_T1C::getInstance()->trip2step(MotorVars_T1C::nGrapSleeveOffsetY, E_MTT1C_MAG_SLEEVE, stCfgMotorParams.fGrapSleeveOffsetY);
    else
        AlgorithmBLL_T1C::getInstance()->step2trip(stCfgMotorParams.fGrapSleeveOffsetY, E_MTT1C_MAG_SLEEVE, MotorVars_T1C::nGrapSleeveOffsetY);

    if(0 < stCfgMotorParams.fGrapSleeveOffsetY2)
        AlgorithmBLL_T1C::getInstance()->trip2step(MotorVars_T1C::nGrapSleeveOffsetY2, E_MTT1C_MAG_SLEEVE, stCfgMotorParams.fGrapSleeveOffsetY2);
    else
        AlgorithmBLL_T1C::getInstance()->step2trip(stCfgMotorParams.fGrapSleeveOffsetY2, E_MTT1C_MAG_SLEEVE, MotorVars_T1C::nGrapSleeveOffsetY2);

    if(0 < stCfgMotorParams.fMixingSleeveOffsetY)
        AlgorithmBLL_T1C::getInstance()->trip2step(MotorVars_T1C::nMixingSleeveOffsetY, E_MTT1C_MAG_SLEEVE, stCfgMotorParams.fMixingSleeveOffsetY);
    else
        AlgorithmBLL_T1C::getInstance()->step2trip(stCfgMotorParams.fMixingSleeveOffsetY, E_MTT1C_MAG_SLEEVE, MotorVars_T1C::nMixingSleeveOffsetY);

    if(0 < stCfgMotorParams.fMagneticMaxOffsetY)
        AlgorithmBLL_T1C::getInstance()->trip2step(MotorVars_T1C::nMagneticMaxOffsetY, E_MTT1C_MAG_ROD, stCfgMotorParams.fMagneticMaxOffsetY);
    else
        AlgorithmBLL_T1C::getInstance()->step2trip(stCfgMotorParams.fMagneticMaxOffsetY, E_MTT1C_MAG_ROD, MotorVars_T1C::nMagneticMaxOffsetY);

    if(0 < stCfgMotorParams.fPierceOffsetY)
        AlgorithmBLL_T1C::getInstance()->trip2step(MotorVars_T1C::nPierceOffsetY, E_MTT1C_VERTIAL, stCfgMotorParams.fPierceOffsetY);
    else
        AlgorithmBLL_T1C::getInstance()->step2trip(stCfgMotorParams.fPierceOffsetY, E_MTT1C_VERTIAL, MotorVars_T1C::nPierceOffsetY);

    if(0 < stCfgMotorParams.fGrapTipsOffsetY)
        AlgorithmBLL_T1C::getInstance()->trip2step(MotorVars_T1C::nGrapTipsOffsetY, E_MTT1C_VERTIAL, stCfgMotorParams.fGrapTipsOffsetY);
    else
        AlgorithmBLL_T1C::getInstance()->step2trip(stCfgMotorParams.fGrapTipsOffsetY, E_MTT1C_VERTIAL, MotorVars_T1C::nGrapTipsOffsetY);

    if(0 < stCfgMotorParams.fTipsMixingOffsetY)
        AlgorithmBLL_T1C::getInstance()->trip2step(MotorVars_T1C::nTipsMixingOffsetY, E_MTT1C_VERTIAL, stCfgMotorParams.fTipsMixingOffsetY);
    else
        AlgorithmBLL_T1C::getInstance()->step2trip(stCfgMotorParams.fTipsMixingOffsetY, E_MTT1C_VERTIAL, MotorVars_T1C::nTipsMixingOffsetY);

    if(0 < stCfgMotorParams.fExtSwallowOffsetY)
        AlgorithmBLL_T1C::getInstance()->trip2step(MotorVars_T1C::nExtSwallowOffsetY, E_MTT1C_VERTIAL, stCfgMotorParams.fExtSwallowOffsetY);
    else
        AlgorithmBLL_T1C::getInstance()->step2trip(stCfgMotorParams.fExtSwallowOffsetY, E_MTT1C_VERTIAL, MotorVars_T1C::nExtSwallowOffsetY);

    if(0 < stCfgMotorParams.fExtSpitOffsetY)
        AlgorithmBLL_T1C::getInstance()->trip2step(MotorVars_T1C::nExtSpitOffsetY, E_MTT1C_VERTIAL, stCfgMotorParams.fExtSpitOffsetY);
    else
        AlgorithmBLL_T1C::getInstance()->step2trip(stCfgMotorParams.fExtSpitOffsetY, E_MTT1C_VERTIAL, MotorVars_T1C::nExtSpitOffsetY);
}
